
package com.eltonkent.db;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.eltonkent.security.BFEncryptionEngine;
import com.eltonkent.ui.containers.DialogFolderListContainer;
import com.eltonkent.ui.containers.FolderDetailsContainer;
import com.eltonkent.ui.containers.FolderListContainer;

public final class FolderListTable extends GenericTable
{
	public static final String TABLE_NAME = "TBL_FOLDER_LIST";
	private static final String COL_FOLDER_NAME = "FOLDER_NAME";
	private final String COL_CREATED_ON = "CREATED_ON";
	private static final String COL_FOLDER_DESC = "FOLDER_DESCRIPTION";
	private final String COL_COUNT = "ITEM_COUNT";
	private final String COL_ID = "FOLDER_ID";
	private final String COL_FOLDER_ICON = "FOLDER_TYPE";
	private final String COL_LOCK_STATUS = "LOCK_STATUS";
	private final String COL_LOCKED_PASSWORD = "FOLDER_PASSWORD";
	private final String COL_LAST_ACCESSED = "LAST_ACCESSED";
	private final String COL_TOTAL_ENTRIES = "TOTAL_ENTRIES";

	FolderListTable()
	{
	}

	public FolderListTable(Context context)
	{
		super(context);
	}

	private void addEntry(SQLiteDatabase database, String folderName, String description, String icon)
	{
		ContentValues values = new ContentValues();
		values.put(COL_FOLDER_NAME, folderName);
		values.put(COL_FOLDER_DESC, description);
		values.put(COL_CREATED_ON, getDateAsString());
		values.put(COL_COUNT, 1);
		values.put(COL_FOLDER_ICON, icon);
		database.insert(TABLE_NAME, null, values);
	}

	public void addFolder(String folderName, String description, String icon, String password)
	{
		addEntry(getDatabase(), folderName, description, icon);
		setFolderPassword(getDatabase(), folderName, password);
		closeDB();
	}

	public void deleteFolder(String folderName)
	{
		SQLiteDatabase database = getDatabase();
		database.delete(TABLE_NAME, COL_FOLDER_NAME + "='" + folderName + "'", null);
		database.delete(SafeEntryTable.TABLE_NAME,
				SafeEntryTable.COL_FOLDER_NAME + "='" + folderName + "'", null);
		closeDB();
	}

	@Override
	void doAfterTableCreate(SQLiteDatabase database)
	{
		// Log.d("DB", "After table create called for FOLDER LIST");
		addEntry(database, "Banks", "test description", "folder/public.png");
		addEntry(database, "Internet", "test description", "folder/internet.png");
		addEntry(database, "General", "test description", "folder/internet.png");
		addEntry(database, "Person", "test description", "folder/personal.png");
		setFolderPassword(database, "Person", "test");
	}

	public boolean doesFolderExist(String folderName)
	{
		Cursor cursor = getDatabase().query(TABLE_NAME, new String[]
		{ COL_FOLDER_NAME }, null, null, null, null, null, null);
		cursor.moveToFirst();
		int indx = cursor.getColumnIndex(COL_FOLDER_NAME);

		for(int i = 0; i < cursor.getCount(); i++)
		{
			if(cursor.getString(indx).equals(folderName))
			{
				cursor.close();
				closeDB();
				return true;
			}
			cursor.moveToNext();
		}
		cursor.close();
		closeDB();
		return false;
	}

	private String getDateAsString()
	{
		SimpleDateFormat date = new SimpleDateFormat("yyyy.MM.dd hh:mm");
		return date.format(new Date(System.currentTimeMillis()));
	}

	public FolderDetailsContainer[] getFolderDetails(String[] leftTitles, String folderName)
	{
		Cursor cursor = getDatabase().query(TABLE_NAME, new String[]
		{ COL_FOLDER_DESC, COL_CREATED_ON, COL_LOCK_STATUS, COL_TOTAL_ENTRIES, },
				COL_FOLDER_NAME + "='" + folderName + "'", null, null, null, null);
		cursor.moveToFirst();
		FolderDetailsContainer[] container = new FolderDetailsContainer[leftTitles.length];

		for(int i = 0; i < leftTitles.length; i++)
		{
			container[i] = new FolderDetailsContainer(leftTitles[i], "Test data");
		}
		closeDB();

		return container;
	}

	public String getFolderPassword(String folderName)
	{
		Cursor cursor = getDatabase().query(TABLE_NAME, new String[]
		{ COL_LOCKED_PASSWORD }, COL_FOLDER_NAME + "= '" + folderName + "'", null, null, null, null, null);
		cursor.moveToFirst();
		int idx = cursor.getColumnIndex(COL_LOCKED_PASSWORD);
		byte[] password = cursor.getBlob(idx);
		cursor.close();
		password = BFEncryptionEngine.getInstance().decrypt(password);
		String pass = null;
		try
		{
			pass = new String(password, "UTF-8");
		} catch(UnsupportedEncodingException e)
		{
			e.printStackTrace();
		}
		closeDB();
		return pass;
	}

	public FolderListContainer[] getFolders()
	{
		Cursor data = getDatabase().query(TABLE_NAME, new String[]
		{ COL_FOLDER_NAME, COL_FOLDER_DESC, COL_FOLDER_ICON, COL_LOCK_STATUS }, null, null, null, null,
				null);
		data.moveToFirst();
		FolderListContainer[] folderList = new FolderListContainer[data.getCount()];
		int idx1 = data.getColumnIndex(COL_FOLDER_NAME);
		int idx2 = data.getColumnIndex(COL_FOLDER_DESC);
		int idx3 = data.getColumnIndex(COL_FOLDER_ICON);
		int idx4 = data.getColumnIndex(COL_LOCK_STATUS);
		int lockStatus;
		for(int i = 0; i < data.getCount(); i++)
		{
			lockStatus = data.getInt(idx4);
			folderList[i] = new FolderListContainer(data.getString(idx1), data.getString(idx2), data
					.getString(idx3), lockStatus == FolderListContainer.LOCK_LOCKED);
			data.moveToNext();
		}
		data.close();
		closeDB();
		return folderList;
	}

	/**
	 * Get the list of folders except the current folder
	 * 
	 * @param currentFolder
	 * @return
	 */
	public DialogFolderListContainer[] getFoldersOnly(String currentFolder)
	{
		Cursor data = getDatabase().query(TABLE_NAME, new String[]
		{ COL_FOLDER_NAME, COL_FOLDER_ICON }, null, null, null, null, null);
		data.moveToFirst();
		DialogFolderListContainer[] folderList = new DialogFolderListContainer[data.getCount() - 1];
		int idx1 = data.getColumnIndex(COL_FOLDER_NAME);
		int idx2 = data.getColumnIndex(COL_FOLDER_ICON);
		String current;
		int index = 0;
		for(int i = 0; i < data.getCount(); i++)
		{
			current = data.getString(idx1);
			if(!current.equals(currentFolder))
			{
				folderList[index] = new DialogFolderListContainer(current, data.getString(idx2));
				index++;
			}
			data.moveToNext();
		}
		data.close();
		closeDB();
		return folderList;
	}

	@Override
	List<Field> getTableFields()
	{
		List<Field> fields = new ArrayList<Field>();
		fields.add(new Field(COL_ID, "integer primary key autoincrement"));
		fields.add(new Field(COL_FOLDER_NAME, "text"));
		fields.add(new Field(COL_CREATED_ON, "text"));
		fields.add(new Field(COL_FOLDER_DESC, "text"));
		fields.add(new Field(COL_LOCK_STATUS, "integer"));
		fields.add(new Field(COL_LOCKED_PASSWORD, "blob"));
		fields.add(new Field(COL_COUNT, "integer"));
		fields.add(new Field(COL_FOLDER_ICON, "text"));
		fields.add(new Field(COL_LAST_ACCESSED, "text"));
		fields.add(new Field(COL_TOTAL_ENTRIES, "integer"));
		return fields;
	}

	@Override
	String getTableName()
	{
		return TABLE_NAME;
	}

	public void removeFolderPassword(String folderName)
	{
		setFolderPassword(getDatabase(), folderName, null);
		closeDB();
	}

	/**
	 * Used to set/reset or remove the password for a folder
	 * 
	 * @param folderName
	 * @param password
	 */
	private void setFolderPassword(SQLiteDatabase database, String folderName, String password)
	{
		ContentValues values = new ContentValues();
		if(password == null)
		{
			values.put(COL_LOCKED_PASSWORD, new byte[]
			{ 0 });
			values.put(COL_LOCK_STATUS, FolderListContainer.LOCK_UNLOCKED);
		} else
		{
			values.put(COL_LOCK_STATUS, FolderListContainer.LOCK_LOCKED);
			// Log.e("DB", "Folder entry has password");
			try
			{
				byte[] pass = password.getBytes("UTF-8");
				values.put(COL_LOCKED_PASSWORD, BFEncryptionEngine.getInstance().encrypt(pass));
			} catch(UnsupportedEncodingException e)
			{
				e.printStackTrace();
			}
		}
		database.update(TABLE_NAME, values, COL_FOLDER_NAME + "='" + folderName + "'", null);
	}

	public void setFolderPassword(String folderName, String password)
	{
		setFolderPassword(getDatabase(), folderName, password);
	}

	public void updateFolder(String oldFolderName, String newFolderName, String description)
	{
		SQLiteDatabase database = getDatabase();
		ContentValues values = new ContentValues();
		values.put(COL_FOLDER_NAME, newFolderName);
		database.update(SafeEntryTable.TABLE_NAME, values, SafeEntryTable.COL_FOLDER_NAME + "='"
				+ oldFolderName + "'", null);
		values.put(COL_FOLDER_DESC, description);
		database.update(TABLE_NAME, values, COL_FOLDER_NAME + "='" + oldFolderName + "'", null);
		// TODO update entries in other tables as well
		closeDB();
	}

	@Override
	public void deSerialize(DataInputStream dis) throws IOException
	{
		getDatabase().delete(TABLE_NAME, null, null);

		int count = dis.readInt();
		int lockstat;
		for(int i = 0; i < count; i++)
		{

			ContentValues values = new ContentValues();
			values.put(COL_FOLDER_NAME, dis.readUTF());
			values.put(COL_CREATED_ON, dis.readUTF());
			values.put(COL_FOLDER_DESC, dis.readUTF());
			values.put(COL_FOLDER_ICON, dis.readUTF());
			lockstat = dis.readInt();
			if(lockstat == FolderListContainer.LOCK_LOCKED)
			{
				// Log.d("UI", "Folder has password");
				int len = dis.readInt();
				byte[] pwd = new byte[len];
				dis.read(pwd);
				values.put(COL_LOCKED_PASSWORD, pwd);
				values.put(COL_LOCK_STATUS, FolderListContainer.LOCK_LOCKED);
			} else
			{
				values.put(COL_LOCKED_PASSWORD, new byte[]
				{ 0 });
				values.put(COL_LOCK_STATUS, FolderListContainer.LOCK_UNLOCKED);
			}
			getDatabase().insert(TABLE_NAME, null, values);
		}
		closeDB();
	}

	@Override
	public void serialize(DataOutputStream dos) throws IOException
	{
		Cursor cursor = getDatabase().query(
				TABLE_NAME,
				new String[]
				{ COL_FOLDER_NAME, COL_CREATED_ON, COL_FOLDER_DESC, COL_FOLDER_ICON, COL_LOCK_STATUS,
						COL_LOCKED_PASSWORD }, null, null, null, null, null);
		cursor.moveToFirst();
		int indxName = cursor.getColumnIndex(COL_FOLDER_NAME);
		int indxCreatedOn = cursor.getColumnIndex(COL_CREATED_ON);
		int indxDesc = cursor.getColumnIndex(COL_FOLDER_DESC);
		int indxIcon = cursor.getColumnIndex(COL_FOLDER_ICON);
		int indxLockStat = cursor.getColumnIndex(COL_LOCK_STATUS);
		int indxLockPass = cursor.getColumnIndex(COL_LOCKED_PASSWORD);
		dos.writeInt(cursor.getCount());
		for(int i = 0; i < cursor.getCount(); i++)
		{
			dos.writeUTF(cursor.getString(indxName));
			dos.writeUTF(cursor.getString(indxCreatedOn));
			dos.writeUTF(cursor.getString(indxDesc));
			dos.writeUTF(cursor.getString(indxIcon));
			int lockStatus = cursor.getInt(indxLockStat);
			dos.writeInt(lockStatus);
			if(lockStatus == FolderListContainer.LOCK_LOCKED)
			{
				byte[] folderPass = cursor.getBlob(indxLockPass);
				dos.writeInt(folderPass.length);
				dos.write(folderPass);
			}

			cursor.moveToNext();
		}
		cursor.close();
		closeDB();

	}
}
